package com.spdd.mt.biz.manager.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import com.spdd.mt.biz.config.ConfigBean;
import com.spdd.mt.biz.config.SpddMapping;
import com.spdd.mt.biz.constant.ResponseCode;
import com.spdd.mt.biz.exception.BusinessException;
import com.spdd.mt.biz.manager.model.WebRequest;
import com.spdd.mt.common.util.DateUtils;
import com.spdd.mt.common.util.JacksonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.Set;


/**
 * 签名校验服务
 *
 * @since 2025年04月03日
 */
@Slf4j
@Service
public class SignService {

    @Autowired
    private ConfigBean configBean;

    @Autowired
    private SpddMapping spddMapping;

    /**
     * 加密一个实体
     *
     * @param bean 实体
     */
    public String sign(Object bean, String merchNo) {
        Map<String, Object> beanMap = JacksonUtils.toObj(JacksonUtils.toJson(bean), Map.class);


        String context = buildContext(beanMap, merchNo);
        return MD5.create().digestHex(context);
    }

    public <T extends WebRequest> T buildSignRequest(T request, String merchNo) {
        String sign = sign(request, merchNo);
        request.setSign(sign);
        request.setSignType("md5");
        request.setTimestamp(DateUtils.getTimestamp());
        request.setVersion("1.0");

        return request;
    }

    /**
     * 签名校验
     *
     * @param requestMap 校验的参数
     */
    public void validateSign(Map<String, Object> requestMap) {
        log.info("签名校验参数:{}", requestMap);

        String merchNo = (String) requestMap.get("merchNo");
        if (StrUtil.isBlank(merchNo)) {
            throw new BusinessException(ResponseCode.PARAM_SIGN_ERROR, "获取签名key失败,商户号为空");
        }
        if (CollectionUtil.isNotEmpty(configBean.getUnverifiedAppIds()) && configBean.getUnverifiedAppIds().contains(merchNo)) {
            log.info("merchNo: {} 不校验签名", requestMap.get("merchNo"));
            return;
        }
        // if (!publicKeys.keySet().contains(appId)) {
        //     log.info("AppId:{}非法", appId);
        //     throw new BusinessException(ErrorCodeEnum.ACCOUNT_ERROR);
        // }
        String context = buildContext(requestMap, merchNo);
        log.info("签名原文:[{}]", context);
        if (StrUtil.isBlank(context)) {
            log.info("构造签名报文失败");
            throw new BusinessException(ResponseCode.PARAM_SIGN_ERROR);
        }

        String sign = String.valueOf(requestMap.get("sign"));
        if (StrUtil.isBlank(sign)) {
            log.info("获取Http请求签名值为空");
            throw new BusinessException(ResponseCode.PARAM_SIGN_ERROR);
        }
        String checkSign = MD5.create().digestHex(context);
        log.info("签名密文:[{}]", checkSign);

        boolean flag = StrUtil.equalsIgnoreCase(sign, checkSign);
        log.info("验签结果:{}", flag);

        if (!flag) {
            throw new BusinessException(ResponseCode.PARAM_SIGN_ERROR);
        }
    }

    private String buildContext(Map<String, Object> requestMap, String merchNo) {
        if (StrUtil.isBlank(merchNo)) {
            throw new BusinessException(ResponseCode.PARAM_SIGN_ERROR, "获取签名key失败,商户号为空");
        }
        // 获取签名秘钥
        SpddMapping.AppInfo appInfo = spddMapping.getMapping().get(merchNo);
        if (Objects.isNull(appInfo)) {
            throw new BusinessException(ResponseCode.PARAM_SIGN_ERROR, "获取签名key失败,商户不存在");
        }
        String partnerKey = appInfo.getPartnerKey();

        try {
            Set<String> keySet = requestMap.keySet();
            String[] keyArray = keySet.toArray(new String[0]);
            Arrays.sort(keyArray);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < keyArray.length; i++) {
                if ("sign".equals(keyArray[i])) {
                    continue;
                }
                // 参数值为空，则不参与签名
                if (String.valueOf(requestMap.get(keyArray[i])).isEmpty()) {
                    continue;
                }
                // 格式为：key1value1key2value2
                sb.append(keyArray[i]).append(requestMap.get(keyArray[i]));
                // if (i < keyArray.length - 1) {
                //     sb.append("");
                // }
            }
            sb.append(partnerKey);
            return sb.toString();
        } catch (Exception e) {
            log.error("构造签名报文异常", e);
            return null;
        }
    }
}
